import Bullet, { BulletHit, Contact } from "./bullet";

const { ccclass, property } = cc._decorator;


@ccclass
export default class SpriteBullet extends Bullet {
    onGrab(other: Bullet): void {
        super.onGrab(other);
        this.speed = cc.v2();
    }
    onDrop(other: Bullet): void {
        super.onDrop(other);
    }
    updateStand(dt: number, hit: BulletHit) {
        //计算速度Y的差距
        let deltaY = this.speed.y - hit.other.speed.y;
        let deltaDisY = Math.abs(3 * deltaY * dt);
        if (this.speed.y < 0 && this.canStandOnIt(hit.other) && !this.isStandOnIt(hit.other)) {
            if (Math.abs((hit.other.node.y + hit.other.node.height / 2) - (this.node.y - this.node.height / 2)) < deltaDisY) {
                this.standOn(hit.other);
                return true;
            }
        }
        return false;
    }
    updateSpeed(dt: number) {
        let dv = this.speed.mul(dt);
        let dstPos = this.curPos.add(dv);
        this.curPos = dstPos;

        // this.speed = this.speed.mul(this.damping / 100).add(this.world.gravity.mul(this.gravityScale / 100));
        this.speed.x *=this.damping/100;
        this.speed = this.speed.add(this.world.gravity.mul(this.gravityScale / 100).mul(dt));


        if (cc.isValid(this.stand)) {
            if (this.stand.detaching && this.speed.y < 0) {
                this.stand.detaching = false;
            }
            if (!this.stand.detaching) {
                this.speed.y = 0;
            }
        }

        this.speed.x = Math.max(-this.speedMax.x, Math.min(this.speedMax.x, this.speed.x));
        this.speed.y = Math.max(-this.speedMax.y, Math.min(this.speedMax.y, this.speed.y));
    }

    update(dt: number) {
        super.update(dt);
        if (!this.physicsEnabled) {
            return;
        }

        let solidV2 = cc.v2();
        let elastic = this.elastic / 100;
        for (let i = 0; i < this.hits.length;) {
            let hit = this.hits[i];

            if (hit.other.physicsEnabled && !hit.other.isSensor) {
                for (let c = 0; c < hit.contacts.length; c++) {
                    let contact = hit.contacts[c];
                    //反弹
                    if (!this.isStandOnIt(hit.other) && this.isStandOnYou(hit.other)) {

                        if (this.speed.y < 0 && contact.normal.y === 1) {
                            this.speed.y *= -elastic;
                        }
                        // else if (this.speed.y > 0 && contact.normal.y === -1) {
                        //     this.speed.y *= elastic;
                        // }
                    }

                    if (!this.isStandOnIt(hit.other)) {
                        if (this.deltaPos.x < 0 && contact.normal.x === 1) //左
                        {
                            let w = this.col.size.width / 2 + hit.other.col.size.width / 2;
                            let wn = this.node.x - hit.other.node.x;
                            if (wn < w) {
                                if (hit.other.isSolid) {
                                    solidV2.x += w - wn;
                                }
                                if (this.speed.x < 0) {
                                    this.speed.x *= -elastic;
                                }
                            }
                        }
                        else if (this.deltaPos.x > 0 && contact.normal.x < 0) //右
                        {
                            let w = this.col.size.width / 2 + hit.other.col.size.width / 2;
                            let wn = hit.other.node.x - this.node.x;
                            if (wn < w) {
                                if (hit.other.isSolid) {
                                    solidV2.x -= w - wn;
                                }
                                if (this.speed.x > 0) {
                                    this.speed.x *= -elastic;
                                }
                            }
                        }

                        if (this.deltaPos.y < 0 && contact.normal.y === 1) //底部
                        {
                            let w = this.col.size.height / 2 + hit.other.col.size.height / 2;
                            let wn = this.node.y - hit.other.node.y;
                            if (wn < w) {
                                // if (hit.other.isSolid) {
                                //     solidV2.y += w - wn;
                                // }
                                if (this.speed.y < 0) {
                                    this.speed.y *= -elastic;
                                }
                            }
                        }
                        else if (this.deltaPos.y > 0 && contact.normal.y === -1) //顶
                        {
                            let sp = cc.v2(this.node.position);
                            let op = cc.v2(hit.other.node.position);
                            //down
                            let od = [
                                op.add(cc.v2(-hit.other.col.size.width / 2, -hit.other.col.size.height / 2)),
                                op.add(cc.v2(hit.other.col.size.width / 2, -hit.other.col.size.height / 2)),
                            ];
                            if (!Bullet.FuzzyEqualsV2Arr(contact.loc, od, 25)) {
                                let w = this.col.size.height / 2 + hit.other.col.size.height / 2;
                                let wn = hit.other.node.y - this.node.y;
                                if (wn < w) {
                                    // if (hit.other.isSolid) {
                                    //     solidV2.y -= w - wn;
                                    // }
                                    if (this.speed.y > 0) {
                                        this.speed.y *= -elastic;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            i++;
        }

        this.node.x += solidV2.x;
        this.node.y += solidV2.y;
    }

    createCollision(other: Bullet) {
        if (!this.physicsEnabled) {
            return;
        }
        if (!other.physicsEnabled) {
            return;
        }
        let hit = new BulletHit();
        hit.self = this;
        hit.other = other;

        this.updateCollision(hit, other);
        return hit;

    }

    onCollisionEnter(other: cc.BoxCollider, self: cc.BoxCollider) {
        if (!this.physicsEnabled) {
            return;
        }
        let otherBullet = other.getComponent(Bullet);
        if (!otherBullet) {
            return;
        }
        if (!otherBullet.physicsEnabled) {
            return;
        }
        if (otherBullet.isSensor) {
            return;
        }

        let hit = this.createCollision(otherBullet);
        if (hit) {
            this.hits.push(hit);
        }
    }
    onCollisionExit(other: cc.BoxCollider, self: cc.BoxCollider) {
        let ind = this.hits.findIndex(hit => {
            return hit.other.col === other
        });
        let hit: BulletHit = null;
        if (ind !== -1) {
            hit = this.hits.splice(ind, 1)[0];
            // if (this.state === BulletState.Stand) {
            //     if (hit == this.landHit) {
            //         if (Math.abs((hit.other.node.y + hit.other.node.height / 2) - (this.node.y - this.node.height / 2)) > 25) {
            //             this.landHit = null;
            //             this.state = BulletState.Physics;
            //         }
            //     }
            // }
        }
    }
    onCollisionStay(other: cc.BoxCollider, self: cc.BoxCollider) {
        if (!this.physicsEnabled) {
            return;
        }
        let otherBullet = other.getComponent(Bullet);
        if (!otherBullet) {
            return;
        }
        if (!otherBullet?.physicsEnabled) {
            return;
        }
        let hit = this.getHitByOtherBullet(otherBullet);
        if (hit) {
            this.updateCollision(hit, otherBullet);
        }
        else {
            let hit = this.createCollision(otherBullet);
            if (hit) {
                this.hits.push(hit);
            }
        }
    }
    updateCollision(hit: BulletHit, other: Bullet) {
        hit.contacts = [];

        let sp = cc.v2(this.node.position);
        let op = cc.v2(other.node.position);

        //todo: 中点延长线碰撞

        //4边碰撞
        //left
        let sl = [
            sp.add(cc.v2(-this.col.size.width / 2, -this.col.size.height / 2)),
            sp.add(cc.v2(-this.col.size.width / 2, this.col.size.height / 2)),
        ];
        //right
        let sr = [
            sp.add(cc.v2(this.col.size.width / 2, -this.col.size.height / 2)),
            sp.add(cc.v2(this.col.size.width / 2, this.col.size.height / 2)),
        ];
        //top
        let st = [
            sp.add(cc.v2(-this.col.size.width / 2, this.col.size.height / 2)),
            sp.add(cc.v2(this.col.size.width / 2, this.col.size.height / 2)),
        ];
        //down
        let sd = [
            sp.add(cc.v2(-this.col.size.width / 2, -this.col.size.height / 2)),
            sp.add(cc.v2(this.col.size.width / 2, -this.col.size.height / 2)),
        ];

        //left
        let ol = [
            op.add(cc.v2(-other.col.size.width / 2, -other.col.size.height / 2)),
            op.add(cc.v2(-other.col.size.width / 2, other.col.size.height / 2)),
        ];
        //right
        let or = [
            op.add(cc.v2(other.col.size.width / 2, -other.col.size.height / 2)),
            op.add(cc.v2(other.col.size.width / 2, other.col.size.height / 2)),
        ];
        //top
        let ot = [
            op.add(cc.v2(-other.col.size.width / 2, other.col.size.height / 2)),
            op.add(cc.v2(other.col.size.width / 2, other.col.size.height / 2)),
        ];
        //down
        let od = [
            op.add(cc.v2(-other.col.size.width / 2, -other.col.size.height / 2)),
            op.add(cc.v2(other.col.size.width / 2, -other.col.size.height / 2)),
        ];

        // ||->=
        let slot = Bullet.SegmentsIntr(sl, ot);
        let srot = Bullet.SegmentsIntr(sr, ot);
        let slod = Bullet.SegmentsIntr(sl, od);
        let srod = Bullet.SegmentsIntr(sr, od);

        let stol = Bullet.SegmentsIntr(st, ol);
        let sdol = Bullet.SegmentsIntr(sd, ol);
        let stor = Bullet.SegmentsIntr(st, or);
        let sdor = Bullet.SegmentsIntr(sd, or);

        let edgeRange = 2;
        //self交点
        if (slot) {
            if (edgeRange < Math.abs(sl[0].x - or[0].x)) {
                hit.contacts.push(new Contact(slot, cc.v2(0, 1)));
            }
        }
        else if (srot) {
            if (edgeRange < Math.abs(sr[0].x - ol[0].x)) {
                hit.contacts.push(new Contact(srot, cc.v2(0, 1)));
            }
        }
        if (slod) {
            if (edgeRange < Math.abs(sl[0].x - or[0].x)) {
                hit.contacts.push(new Contact(slod, cc.v2(0, -1)));
            }
        }
        else if (srod) {
            if (edgeRange < Math.abs(sr[0].x - ol[0].x)) {
                hit.contacts.push(new Contact(srod, cc.v2(0, -1)));
            }
        }

        if (stol) {
            if (edgeRange < Math.abs(st[0].y - od[0].y)) {
                hit.contacts.push(new Contact(stol, cc.v2(-1, 0)));
            }
        }
        else if (sdol) {
            if (edgeRange < Math.abs(sd[0].y - ot[0].y)) {
                hit.contacts.push(new Contact(sdol, cc.v2(-1, 0)));
            }
        }
        if (stor) {
            if (edgeRange < Math.abs(st[0].y - od[0].y)) {
                hit.contacts.push(new Contact(stor, cc.v2(1, 0)));
            }
        }
        else if (sdor) {
            if (edgeRange < Math.abs(sd[0].y - ot[0].y)) {
                hit.contacts.push(new Contact(sdor, cc.v2(1, 0)));
            }
        }
    }
};

// onCollisionStay(other: cc.BoxCollider, self: cc.BoxCollider) {
//     // if (this.state === BulletState.Physics) {
//     //     if (this.checkLand(other)) {
//     //         this.land = other;
//     //         this.state = BulletState.Stand;
//     //     }
//     // }


// }
